package se19team1e.controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import se19team1e.dao.abstrakt.jaas.CompanyDAO;
import se19team1e.dao.abstrakt.jaas.DepartmentDAO;
import se19team1e.dao.abstrakt.jaas.JobAdvertDAO;
import se19team1e.dao.factory.DAOFactory;
import se19team1e.dao.factory.DAOFactorySelector;
import se19team1e.entity.CompanyDTO;
import se19team1e.entity.DepartmentDTO;
import se19team1e.entity.JobAdvertDTO;
import se19team1e.exception.DataAccessException;
import se19team1e.gui.JobAdvertSearchForm;
import se19team1e.gui.WithdrawJobAdvertScreen;
import se19team1e.search.SearchEngine;

/**
 * 
 * The withdraw job advertisement  controller class coordinates the operations between
 * the screen, form, and entity objects for withdraw job advert. It extends from
 * the base controller class.
 * 
 * @see JobAdvertDTO , CreateJobAdvertController
 * @author Nasri Bin Najib
 * 
 */
public class WithdrawJobAdvertController extends BaseController {

	/**
	 * Constructs the controller.
	 * 
	 * @param application
	 *            Reference to the current application instance.
	 */
	public WithdrawJobAdvertController(Application application) {
		super(application);
	}

	/**
	 * Initializes the controller.
	 * 
	 * <p>
	 * The withdraw job advert form is initialized and set as the current active
	 * screen.
	 * </p>
	 * <p>
	 * Initialization involves the retrieval of all companies and departments in
	 * the system.
	 * </p>
	 * 
	 * @param jobAdvertId
	 *            Job Advert Id to withdraw.
	 * @throws DataAccessException
	 *             Error retrieving the job advert, or withdrawing.
	 */
	public void initialize(String jobAdvertId) throws DataAccessException {
		DAOFactory daoFactory = DAOFactorySelector.getDAOFactory();

		// get job advert
		JobAdvertDAO jobAdvertDAO = daoFactory.getJobAdvertDAO();
		JobAdvertDTO jobAdvert = jobAdvertDAO.retrieveById(jobAdvertId);

		// validate, is this job advert eligible?
		if (!this.validate(jobAdvert)) {
			// failure, return
			return;
		}

		// get all companies
		CompanyDAO companyDAO = daoFactory.getCompanyDAO();
		List<CompanyDTO> companies = companyDAO.retrieveAll();

		// get all departments
		DepartmentDAO departmentDAO = daoFactory.getDepartmentDAO();
		List<DepartmentDTO> departments = departmentDAO.retrieveAll();

		// get screen
		WithdrawJobAdvertScreen screen = this.getApplication().getScreen(
				WithdrawJobAdvertScreen.class);

		// initialize screen
		screen.initialize(jobAdvert, this, companies, departments);

		// set as active screen
		this.getApplication().setCurrentScreen(screen);
	}

	/**
	 * Withdraws the specified job advert.
	 * 
	 * @param jobAdvert
	 *            Job advert to withdraw.
	 * @throws DataAccessException
	 *             If error saving the job advert.
	 */
	public void withdrawJobAdvert(JobAdvertDTO jobAdvert)
			throws DataAccessException {
		// validate first
		if (!this.validate(jobAdvert)) {
			// failure, return
			return;
		}

		// withdraw job advert
		doWithdraw(jobAdvert);

		this.saveJobAdvert(jobAdvert);

		this.updateJobAdvertToSearchEngine(jobAdvert);

		// display success message
		this.displayCreateSuccessMessage();
	}

	/**
	 * Perform actual withdraw of the job advert, without saving it yet.
	 * 
	 * <p>
	 * This method is set to package level access for unit testing purpose.
	 * </p>
	 * 
	 * @param jobAdvert
	 *            Job advert to withdraw.
	 */
	void doWithdraw(JobAdvertDTO jobAdvert) {
		jobAdvert.withdraw();
	}

	/**
	 * Validates the job advert to see if it is valid for withdrawal.
	 * 
	 * <p>
	 * It checks if the job advert is not deleted or withdrawn Returns false if
	 * validation fails. Displays an error message if it fails, using a message
	 * box.
	 * </p>
	 * 
	 * @param jobAdvert
	 *            Job advert to withdraw.
	 * @return True if valid.
	 */
	private boolean validate(JobAdvertDTO jobAdvert) {
		return (validateNotDeleted(jobAdvert) && validateNotWithdrawn(jobAdvert));
	}

	/**
	 * Validates if the job advert is already deleted.
	 * 
	 * <p>
	 * This method is set to package level access for unit testing purpose.
	 * </p>
	 * 
	 * @param jobAdvert
	 *            Job advert to validate.
	 * @return True if valid.
	 */
	boolean validateNotDeleted(JobAdvertDTO jobAdvert) {
		if (jobAdvert.isDeleted()) {
			// failure, display error message
			this.displayMessage("Error", "Job Advert already deleted",
					new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent event) {
							// do nothing
						}
					});

			return false;
		}
		return true;
	}

	/**
	 * Validates if the job advert is already withdrawn.
	 * 
	 * <p>
	 * This method is set to package level access for unit testing purpose.
	 * </p>
	 * 
	 * @param jobAdvert
	 *            Job advert to validate.
	 * @return True if valid.
	 */
	boolean validateNotWithdrawn(JobAdvertDTO jobAdvert) {
		if (jobAdvert.isWithdrawn()) {
			// failure, display error message
			this.displayMessage("Error", "Job Advert already withdrawn",
					new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent event) {
							// do nothing
						}
					});

			return false;
		}
		return true;
	}

	/**
	 * Update the job advert to the search engine.
	 * 
	 * <p>
	 * This method is set to package level access for unit testing purpose.
	 * </p>
	 * 
	 * @param jobAdvert
	 *            Job Advert to update to search engine.
	 */
	void updateJobAdvertToSearchEngine(JobAdvertDTO jobAdvert) {
		// update to search engine
		SearchEngine searchEngine = getApplication().getSearchEngine();
		searchEngine.updateIndex(jobAdvert);
	}

	/**
	 * Save the job advert to the persistence storage.
	 * 
	 * <p>
	 * This method is set to package level access for unit testing purpose.
	 * </p>
	 * 
	 * @param jobAdvert
	 *            Job Advert to save.
	 * @throws DataAccessException
	 *             If error saving the job advert.
	 */
	void saveJobAdvert(JobAdvertDTO jobAdvert) throws DataAccessException {
		DAOFactory daoFactory = DAOFactorySelector.getDAOFactory();

		// save job advert
		JobAdvertDAO jobAdvertDAO = daoFactory.getJobAdvertDAO();
		jobAdvertDAO.update(jobAdvert);
	}

	/**
	 * Displays a message box indicating that withdrawn is success
	 */
	void displayCreateSuccessMessage() {
		this.displayMessage("Success", "Job Advert Withdrawn",
				new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent event) {
						// show the search screen again
					    getApplication().selectSearchJobAdvert();
					}
				});
	}

	/**
	 * Shows the search job advert results screen again.
	 * 
	 * <p>
	 * This time, only the screen is set as the active screen, and no further
	 * initialization is asked to be done.
	 * </p>
	 * <p>
	 * This is to retain the previous search results.
	 * </p>
	 */
	public void showSearchJobAdvertResultsScreen() {
		// get screen
		JobAdvertSearchForm screen = this.getApplication().getScreen(
				JobAdvertSearchForm.class);

		// no need to reinitialize, reuse same content.

		// set as active screen
		this.getApplication().setCurrentScreen(screen);
	}

}
